/**
 * Author: ling_feng
 * Date: 2018.5.23
 * CopyRight:
 * 通信类
 */

import MKSocketObserver from './MKSocketObserver'
import MKPacket, { PackMsg } from './MKPacket';
import MKLog from '../MKLog';


export default class MKSocket {
    private m_socket: WebSocket = null;
    private m_observers: Array<MKSocketObserver> = [];
    private m_recvBuffer: ArrayBuffer = new ArrayBuffer(0);
    private m_packageID: number = 0;

    public constructor() {

    }

    /**
     * 链接
     * @param url 地址
     */
    connect(url: string) {
        this.disconnect();

        this.m_socket = new WebSocket(url);
        this.m_socket.binaryType = "arraybuffer";
        this.m_socket.onopen = this.onConnect.bind(this);
        this.m_socket.onmessage = this.onSocketDataReceived.bind(this);
        this.m_socket.onerror = this.onError.bind(this);
        this.m_socket.onclose = this.onClose.bind(this);
    }

    /**
     * 断开
     */
    disconnect() {
        this.m_recvBuffer = new ArrayBuffer(0);
        if (this.m_socket !== null) {
            this.m_socket.onopen = null;
            this.m_socket.onmessage = null;
            this.m_socket.onerror = null;
            this.m_socket.onclose = null;
            this.m_socket.close();
            this.m_socket = null;
            this.m_packageID = 0;
        }
    }

    /**
     * 判断链接
     */
    isConnected() {
        if (this.m_socket !== null) {
            // MKLog.log("[MKSocket] 判断链接 =",this.m_socket.readyState,WebSocket.OPEN);
            return this.m_socket.readyState == WebSocket.OPEN;
        }

        return false;
    }

    /**
     * 发
     * @param msg 数据包
     * @param msgID 
     */
    send(msg, msgID: number) {
        if (!this.isConnected()) {
            return;
        }

        //旧的发送方式
        // var sendMsg:any = this.encodeMsgID(msg, msgID);
        // this.m_socket.send(sendMsg);

        //新的发送方式
        this.m_packageID++;
        let bodyMsg = MKPacket.PackBody(msg);
        var sendMsg: any = this.encodeMsgID(bodyMsg, msgID);
        this.m_socket.send(sendMsg);
        MKLog.log('[MKSocket] msg send msgID =', msgID, ", PackageID =", this.m_packageID);
    }

    addMsgObserver(observer: MKSocketObserver) {
        var find = false;
        for (var i = 0; i < this.m_observers.length; ++i) {
            if (observer === this.m_observers[i]) {
                find = true;
                break;
            }
        }

        if (!find) {
            this.m_observers.push(observer);
        }
    }

    removeObserver(observer: MKSocketObserver) {
        for (var i = 0; i < this.m_observers.length; ++i) {
            if (observer === this.m_observers[i]) {
                observer.onDestroy();
                this.m_observers.splice(i, 1);
                break;
            }
        }
    }

    /**
     * 链接成功
     * @param evt 
     */
    onConnect(evt) {
        MKLog.log("MKSocket [onConnect]");

        for (var i = 0; i < this.m_observers.length; ++i) {
            var observer: MKSocketObserver = this.m_observers[i];
            observer.onConnect(this);
        }
    }

    /**
     * 链接交互
     * @param buffer 数据包
     */
    onMessage(buffer: ArrayBuffer) {
        //旧的接收解析方式
        //var msgData = this.decodeMsgID(buffer);
        // var msgID = msgData.msgID;
        // var msgPackageID = msgData.msgPackageID;
        // var msg = msgData.msg;

        //新的接收解析方式
        var packMsg = MKPacket.Unpack(buffer);
        var msgID = packMsg.msgID;
        var packageID = packMsg.packageID;

        MKLog.log("[MKSocket] msg on msgID =", msgID, ", packageID =", packageID);

        var hasHandler = false;

        for (var i = 0; i < this.m_observers.length; ++i) {
            var observer = this.m_observers[i];
            var isHandled = observer.onMessage(msgID, packMsg);
            if (isHandled) {
                hasHandler = true;
                break;
            }
        }

        if (!hasHandler) {
            MKLog.log("MKSocket err : no socket message handler, messageID = " + msgID);
        }
    }

    /**
     * 链接错误
     * @param evt 
     */
    onError(evt: MessageEvent) {
        for (var i = 0; i < this.m_observers.length; ++i) {
            var observer = this.m_observers[i];
            observer.onError(this);
        }
    }

    /**
     * 链接断开
     * @param evt 
     */
    onClose(evt: MessageEvent) {
        MKLog.log('MKSocket onClose !!!');
        this.disconnect();
        for (var i = 0; i < this.m_observers.length; ++i) {
            var observer = this.m_observers[i];
            observer.onClose(this);
        }
    }

    /**
     * 加密数据
     * @param msg 数据包
     * @param msgID 
     * 包头组合： 0-2:包体长度； 2-6:包体标识； ID； 6-8:消息号；
     * 0 1 2 3 4 5 6 7 8 
     *  |       |     |
     * 长度    标识   消息号
     */
    encodeMsgID(msg: ArrayBuffer, msgID: number) {
        var msgLength = 0;
        if (msg !== null) {
            msgLength = msg.byteLength;
        }

        var allLength = 8 + msgLength;
        var abAll = new ArrayBuffer(allLength);

        var headViewMsgLen = new DataView(abAll, 0, 2);
        headViewMsgLen.setUint16(0, allLength - 2, false);

        var headViewPkgId = new DataView(abAll, 2, 4);
        headViewPkgId.setUint32(0, this.m_packageID, false);

        var headViewMsgId = new DataView(abAll, 6, 2);
        headViewMsgId.setUint16(0, msgID, false);

        if (msgLength != 0) {
            var bodyView = new Int8Array(abAll, 8, msgLength);
            var bobyMsg = new Int8Array(msg);
            bodyView.set(bobyMsg);
        }

        return abAll;
    }

    /**
     * 解析数据
     * @param msg 数据包
     */
    decodeMsgID(msg): { msgID: number, msgPackageID: number, msg: ArrayBuffer } {
        var abAll = msg;
        var headView = new DataView(abAll, 0, 2);
        var msgLength = headView.getUint16(0);

        var abHeaderView = new DataView(abAll, 2, 6);
        var msgProtoIndex = abHeaderView.getUint32(0);
        this.m_packageID = msgProtoIndex;

        var addHeaderView = new DataView(abAll, 6, 2);
        var msgID = addHeaderView.getUint16(0);

        var msgPackageID;
        var msgData = { msgID, msgPackageID, msg };
        msgData.msgID = msgID;
        msgData.msgPackageID = msgProtoIndex;
        msgData.msg = abAll.slice(8, 8 + msgLength);
        return msgData;
    }

    /**
     * 解析返回数据包
     * @param evt 
     */
    onSocketDataReceived(evt: MessageEvent) {
        var bufferData = evt.data;
        var buffer = null;

        var lastLen = this.m_recvBuffer.byteLength;
        if (lastLen > 0) {
            var addLen = bufferData.byteLength;
            var bufferAll = new ArrayBuffer(lastLen + addLen);

            var abLastView = new Int8Array(this.m_recvBuffer);
            var abAllLastView = new Int8Array(bufferAll, 0, lastLen);
            abAllLastView.set(abLastView);

            var abAddView = new Int8Array(bufferData);
            var abAllAddView = new Int8Array(bufferAll, lastLen);
            abAllAddView.set(abAddView);

            buffer = bufferAll;
        }
        else {
            buffer = bufferData;
        }

        var allLength = buffer.byteLength;
        if (allLength < 8) {
            this.m_recvBuffer = buffer;
            return;
        }

        var bufferView = new DataView(buffer);

        var startIdx = 0;
        while (startIdx < allLength) {
            var msgLength = bufferView.getInt16(startIdx);
            var subBufferLength = 2 + msgLength;

            if (startIdx + subBufferLength > allLength) {
                break;
            }

            this.onMessage(buffer.slice(startIdx, startIdx + subBufferLength));
            startIdx += subBufferLength;
        }

        if (startIdx < allLength) {
            this.m_recvBuffer = buffer.slice(startIdx);
        }
        else {
            this.m_recvBuffer = new ArrayBuffer(0);
        }
    }
}